Skip to content

Conversation

@lhotari
Copy link
Member

@lhotari lhotari commented May 6, 2025

Motivation

The current MetadataStore API and MetadataStoreExtended API doesn't provide a way to cancel (unregister) registered listeners. This is a problem in some tests where the metadata store instance is shared, but the brokers are restarted during the test. Notifications will keep on delivered to the broker instances that have already been shutdown.
In addition, to the above problem, the listeners will also keep a strong reference to instances that have already been shutdown, impacting memory usage in some tests.
One of the additional motivations is to cleanup the testing infrastructure so that it would be possible to migrate Pulsar to use the most recent Mockito version, 5.17.0. When mocks are invalidated in newer Mockito versions, they will throw exceptions upon execution. This change is made to ensure that these problems that are currently seen in PR #24241 aren't originating from Metadata Store listeners.

Modifications

Add new methods:

  • registerCancellableListener to MetadataStore
  • registerCancellableSessionListener to MetadataStoreExtended

Make the API binary compatible by adding default methods registerListener and registerSessionListener with the previous method signatures so that plugins using the Metadata API won't break due to this change. Mark these methods deprecated.

Migrate the Pulsar code to use the cancellable methods and store the callback instance for cancellation and use this in the shutdown sequence of each component that registers listeners.

Documentation

  • doc
  • doc-required
  • doc-not-needed
  • doc-complete

@lhotari lhotari added this to the 4.1.0 milestone May 6, 2025
@lhotari lhotari self-assigned this May 6, 2025
@github-actions github-actions bot added the doc-not-needed Your PR changes do not impact docs label May 6, 2025
@lhotari lhotari requested a review from heesung-sohn May 6, 2025 16:20
Copy link
Contributor

@heesung-sohn heesung-sohn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but maybe we need more approvals from others too.

@liangyepianzhou
Copy link
Contributor

liangyepianzhou commented May 7, 2025

@lhotari This test has failed five times, maybe you should look into it.
org.apache.bookkeeper.mledger.impl.ManagedLedgerFactoryShutdownTest.openEncounteredShutdown

* Executing this Runnable will cancel the subscription.
*/
void registerListener(Consumer<Notification> listener);
Runnable registerCancellableListener(Consumer<Notification> listener);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lhotari It looks like this change breaks compatibility with existing implementations of registerListener.
Currently, you always invoke registerCancellableListener, which causes a compile-time failure if the custom metadata store only implements the older registerListener method.
To maintain backward compatibility, registerCancellableListener should delegate to registerListener by default and return a noop runnable. For example:

default Runnable registerCancellableListener(Consumer<Notification> listener) {
    registerListener(listener);
    return () -> {
        // noop
    };
}

@Deprecated
default void registerListener(Consumer<Notification> listener) {
    // noop
}

This ensures compatibility while allowing newer implementations to override registerCancellableListener directly.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you use this way, please add a testcase to cover this change.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like this change breaks compatibility with existing implementations of registerListener.
Currently, you always invoke registerCancellableListener, which causes a compile-time failure if the custom metadata store only implements the older registerListener method.

@nodece That's correct. Binary compatibility would be broken for implementors of the API. Implementors should recompile unless they are already using AbstractBatchedMetadataStore or AbstractMetadataStore base classes. The problem in making both the registerCancellableListener and registerListener a default method is that the compiler won't assist an implementor to implement the method that isn't deprecated.
I'm not aware of implementations that aren't using AbstractBatchedMetadataStore or AbstractMetadataStore base class. The number of implementors is unknown, but I'd assume that the ones that are capable of doing so are also capable of recompiling when upgrading.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

doc-not-needed Your PR changes do not impact docs ready-to-test release/4.0.8

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants